/**
 * Class: PMath
 *
 * Purpose: Math for Processing
 *
 * Created: Jan 20, 2010 @ 4:49:46 PM
 * @author Ken Scott
 */
package org.openfantasia.util.math;

import processing.core.PApplet;

import java.text.DecimalFormat;

public class Math1D {

	public static double[] filter(double[] src, double[] kernal) {
		double[] result = new double[src.length];
		double scale = sum(kernal);
		float r;

		for (int i = 0; i < src.length; i++) {
			r = 0f;
			for (int j = 0; j < kernal.length; j++) {
				if (((i - j) > 0) && ((i - j) < result.length)) {
					r += src[i - j] * kernal[j];
				}
			}
			result[i] = r / scale;
		}

		return result;
	}


	public static float[] filter(float[] src, float[] kernal) {
		float[] result = new float[src.length];
		float scale = sum(kernal);
		float r;

		for (int i = 0; i < src.length; i++) {
			r = 0f;
			for (int j = 0; j < kernal.length; j++) {
				if (((i - j) > 0) && ((i - j) < result.length)) {
					r += src[i - j] * kernal[j];
				}
			}
			result[i] = r / scale;
		}

		return result;
	}


	public static double[] random(double... mags) {
		double[] result = new double[mags.length];
		for (int i = 0; i < mags.length; i++) {
			result[i] = PMath.random(-mags[i], mags[i]);
		}
		return result;
	}


	public static float[] random(float... mags) {
		float[] result = new float[mags.length];
		for (int i = 0; i < mags.length; i++) {
			result[i] = PMath.random(-mags[i], mags[i]);
		}
		return result;
	}


	public static double[] randomAbs(double... mags) {
		double[] result = new double[mags.length];
		for (int i = 0; i < mags.length; i++) {
			result[i] = Math.abs(PMath.random(mags[i]));
		}
		return result;
	}


	public static float[] randomAbs(float... mags) {
		float[] result = new float[mags.length];
		for (int i = 0; i < mags.length; i++) {
			result[i] = Math.abs(PMath.random(mags[i]));
		}
		return result;
	}


	public static double[] add(double[] v1, double[] v2) {
		if (v1.length != v2.length) {
			throw new IllegalArgumentException("Vectors must be the same length (" + v1.length + " or " + v2.length + ")");
		}

		double[] result = new double[v1.length];
		for (int i = 0; i < v1.length; i++) {
			result[i] = v1[i] + v2[i];
		}
		return result;
	}


	public static float[] add(float[] v1, float[] v2) {
		if (v1.length != v2.length) {
			throw new IllegalArgumentException("Vectors must be the same length (" + v1.length + " or " + v2.length + ")");
		}

		float[] result = new float[v1.length];
		for (int i = 0; i < v1.length; i++) {
			result[i] = v1[i] + v2[i];
		}
		return result;
	}


	public static double[] sub(double[] v1, double[] v2) {
		if (v1.length != v2.length) {
			throw new IllegalArgumentException("Vectors must be the same length (" + v1.length + " or " + v2.length + ")");
		}

		double[] result = new double[v1.length];
		for (int i = 0; i < v1.length; i++) {
			result[i] = v1[i] - v2[i];
		}
		return result;
	}


	public static float[] sub(float[] v1, float[] v2) {
		if (v1.length != v2.length) {
			throw new IllegalArgumentException("Vectors must be the same length (" + v1.length + " or " + v2.length + ")");
		}

		float[] result = new float[v1.length];
		for (int i = 0; i < v1.length; i++) {
			result[i] = v1[i] - v2[i];
		}
		return result;
	}


	public static double[] mul(double[] v1, double[] v2) {
		if (v1.length != v2.length) {
			throw new IllegalArgumentException("Vectors must be the same length (" + v1.length + " or " + v2.length + ")");
		}

		double[] result = new double[v1.length];
		for (int i = 0; i < v1.length; i++) {
			result[i] = v1[i] * v2[i];
		}
		return result;
	}


	public static float[] mul(float[] v1, float[] v2) {
		if (v1.length != v2.length) {
			throw new IllegalArgumentException("Vectors must be the same length (" + v1.length + " or " + v2.length + ")");
		}

		float[] result = new float[v1.length];
		for (int i = 0; i < v1.length; i++) {
			result[i] = v1[i] * v2[i];
		}
		return result;
	}


	public static double[] div(double[] v1, double[] v2) {
		if (v1.length != v2.length) {
			throw new IllegalArgumentException("Vectors must be the same length (" + v1.length + " or " + v2.length + ")");
		}

		double[] result = new double[v1.length];
		for (int i = 0; i < v1.length; i++) {
			result[i] = v1[i] / v2[i];
		}
		return result;
	}


	public static float[] div(float[] v1, float[] v2) {
		if (v1.length != v2.length) {
			throw new IllegalArgumentException("Vectors must be the same length (" + v1.length + " or " + v2.length + ")");
		}

		float[] result = new float[v1.length];
		for (int i = 0; i < v1.length; i++) {
			result[i] = v1[i] / v2[i];
		}
		return result;
	}


	public static float dotp(float[] v1, float[] v2) {
		if (v1.length != v2.length) {
			throw new IllegalArgumentException("Vectors must be the same length (" + v1.length + " or " + v2.length + ")");
		}

		float result = 0f;
		for (int i = 0; i < v1.length; i++) {
			result += v1[i] * v2[i];
		}
		return result;
	}


	public static double dotp(double[] v1, double[] v2) {
		if (v1.length != v2.length) {
			throw new IllegalArgumentException("Vectors must be the same length (" + v1.length + " or " + v2.length + ")");
		}

		double result = 0f;
		for (int i = 0; i < v1.length; i++) {
			result += v1[i] * v2[i];
		}
		return result;
	}


	public static double[] addNoise(double[] vector, double frac) {
		double[] result = copy(vector);
		for (int i = 0; i < vector.length; i++) {
			result[i] += PMath.random(frac);
		}
		return result;
	}


	public static float[] addNoise(float[] vector, float frac) {
		float[] result = copy(vector);
		for (int i = 0; i < vector.length; i++) {
			result[i] += PMath.random(frac);
		}
		return result;
	}


	public static double[] mulNoise(double[] vector, double frac) {
		double[] result = copy(vector);
		for (int i = 0; i < vector.length; i++) {
			result[i] *= PMath.random(frac);
		}
		return result;
	}


	public static float[] mulNoise(float[] vector, float frac) {
		float[] result = copy(vector);
		for (int i = 0; i < vector.length; i++) {
			result[i] *= PMath.random(frac);
		}
		return result;
	}


	public static double[] neg(double... vector) {
		double[] result = copy(vector);
		for (int i = 0; i < vector.length; i++) {
			result[i] = -result[i];
		}
		return result;
	}


	public static float[] neg(float... vector) {
		float[] result = copy(vector);
		for (int i = 0; i < vector.length; i++) {
			result[i] = -result[i];
		}
		return result;
	}


	public static double[] abs(double... vector) {
		double[] result = copy(vector);
		for (int i = 0; i < vector.length; i++) {
			result[i] = Math.abs(result[i]);
		}
		return result;
	}


	public static float[] abs(float... vector) {
		float[] result = copy(vector);
		for (int i = 0; i < vector.length; i++) {
			result[i] = Math.abs(result[i]);
		}
		return result;
	}


	public static final double mag(double... v) {
		double s = 0;
		for (double z : v) {
			s += (z * z);
		}
		return Math.sqrt(s);
	}


	public static final float mag(float... v) {
		float[] s = mul(v, v);
		return (float) Math.sqrt((double) sum(s));
	}


	public static double[] scale(double scale, double... vector) {
		double[] result = copy(vector);
		for (int i = 0; i < vector.length; i++) {
			result[i] *= scale;
		}
		return result;
	}


	public static float[] scale(float scale, float... vector) {
		float[] result = copy(vector);
		for (int i = 0; i < vector.length; i++) {
			result[i] *= scale;
		}
		return result;
	}


	public static double sum(double... vector) {
		double result = 0.0d;
		for (int i = 0; i < vector.length; i++) {
			result += vector[i];
		}
		return result;
	}


	public static float sum(float... vector) {
		float result = 0.0f;
		for (int i = 0; i < vector.length; i++) {
			result += vector[i];
		}
		return result;
	}


	public static double avg(double... vector) {
		double result = 0d;
		for (int i = 0; i < vector.length; i++) {
			result += vector[i];
		}
		return result / (double) vector.length;
	}


	public static float avg(float... vector) {
		float result = 0f;
		for (int i = 0; i < vector.length; i++) {
			result += vector[i];
		}
		return result / (float) vector.length;
	}


	public static final double min(double... vector) {
		double result = vector[0];
		for (int i = 1; i < vector.length; i++) {
			double k = vector[i];
			if (k < result) {
				result = k;
			}
		}
		return result;
	}


	public static final float min(float... vector) {
		return PApplet.min(vector);
	}


	public static final double max(double... vector) {
		double result = vector[0];
		for (int i = 1; i < vector.length; i++) {
			double k = vector[i];
			if (k > result) {
				result = k;
			}
		}
		return result;
	}


	public static final float max(float... vector) {
		return PApplet.max(vector);
	}


	public static double[] empty(double... src) {
		return new double[src.length];
	}


	public static float[] empty(float... src) {
		return new float[src.length];
	}


	public static double[] copy(double... vector) {
		double[] result = empty(vector);
		System.arraycopy(vector, 0, result, 0, vector.length);
		return result;
	}


	public static double[] copy(double[] dst, double... src) {
		System.arraycopy(src, 0, dst, 0, dst.length);
		return dst;
	}


	public static float[] toFloat(double... vector) {
		float[] result = new float[vector.length];
		for(int i = 0; i < vector.length; i++) {
			result[i] = (float) vector[i];
		}
		return result;
	}


	public static float[] copy(float... vector) {
		float[] result = empty(vector);
		System.arraycopy(vector, 0, result, 0, vector.length);
		return result;
	}


	public static double[] toDouble(float... vector) {
		double[] result = new double[vector.length];
		for(int i = 0; i < vector.length; i++) {
			result[i] = (double) vector[i];
		}
		return result;
	}


	public static double[] copyFill(double[] vector, double value) {
		double[] result = empty(vector);
		return fill(result, value);
	}


	public static float[] copyFill(float[] vector, float value) {
		float[] result = empty(vector);
		return fill(result, value);
	}


	public static double[] fill(double[] vector, double value) {
		for (int x = 0; x < vector.length; x++) {
			vector[x] = value;
		}

		return vector;
	}


	public static float[] fill(float[] vector, float value) {
		for (int x = 0; x < vector.length; x++) {
			vector[x] = value;
		}

		return vector;
	}


	public static String toString(double... vector) {
		StringBuilder result = new StringBuilder();
		DecimalFormat df = new DecimalFormat("#.###");
		result.append("[");
		for(int i = 0; i < vector.length; i++) {
			if(i > 0) {
				result.append(", ");
			}
			result.append(df.format(vector[i]));
		}
		result.append("]");
		return result.toString();
	}


	public static String toString(float... vector) {
		StringBuilder result = new StringBuilder();
		DecimalFormat df = new DecimalFormat("#.###");
		result.append("[");
		for(int i = 0; i < vector.length; i++) {
			if(i > 0) {
				result.append(", ");
			}
			result.append(df.format(vector[i]));
		}
		result.append("]");
		return result.toString();
	}
}